import type { LngLatLike } from 'mapbox-gl';
import type React from 'react';
import { useEffect, useRef, useState } from 'react';
import MapboxMarker, {
  type MapboxMarkerRef,
} from '@/components/MapView/components/MapboxMarker/Index';
import type { Mapless } from '@/components/MapView/Mapless';
import type { EmitManager } from '../../Mapless/core/manager';
import type { EventPayload, ManagerEvents } from '../../Mapless/index.d';

type SupportedEvents = 'stationsSelected';

type withMapboxMarker<P> = P & {
  /** Mapless实例 */
  mapless: Mapless | undefined;
  /** 地图是否就绪 */
  isMapReady: boolean;
  /** mana名称 */
  manaName: string;
  /** 事件处理函数，返回弹窗内容组件所需的props和位置 */
  onEvent: (eventData: ManagerEvents[SupportedEvents][0]) => {
    props: Partial<P>;
    lngLat: LngLatLike;
  } | null;
  excludeManaNames?: string[];
  eventName?: SupportedEvents;
  destroyOnClose?: boolean;
  markerClassName?: string;
  onClose?: () => void;
};

/**
 * TODO 实验性组件
 * 创建一个高阶组件，用于将任意组件包装为Mapbox弹窗
 * @param WrappedComponent 要包装的组件
 * @returns 包装后的组件
 */
function withMapboxMarker<P>(WrappedComponent: React.ComponentType<P>) {
  const Component: React.FC<withMapboxMarker<P>> = ({
    mapless,
    isMapReady,
    manaName,
    onEvent,
    excludeManaNames = ['SelectTool'],
    eventName = 'stationsSelected',
    destroyOnClose = false,
    markerClassName,
    onClose,
    ...rest
  }) => {
    const markerRef = useRef<MapboxMarkerRef>(null);
    const maplessRef = useRef<Mapless>(undefined);

    const [contentProps, setContentProps] = useState<Partial<P> | null>(null);
    const [position, setPosition] = useState<LngLatLike | null>(null);

    // 处理站点选中事件
    const handleEvent = (...payload: unknown[]) => {
      // TODO sourceName: be careful hardcode
      const eventData = payload[0] as EventPayload;
      if (
        eventData.sourceName &&
        excludeManaNames.includes(eventData.sourceName)
      ) {
        return null;
      }
      const result = onEvent?.(eventData);
      if (result) {
        setContentProps(result.props);
        setPosition(result.lngLat);
        markerRef.current?.show();
        setHide(false);
      } else {
        setContentProps(null);
        setPosition(null);
      }
    };

    // 监听地图事件
    useEffect(() => {
      if (!isMapReady || !mapless || !manaName) return;
      maplessRef.current = mapless;

      mapless.onManaAdd((name, manager) => {
        if (name === manaName) {
          (manager as EmitManager<Record<string, unknown[]>>).on(
            eventName,
            handleEvent,
          );
        }
      });

      // TODO 关注是否有内存泄漏
      return () => {};
    }, [isMapReady, mapless, manaName, eventName, onEvent]);

    const [hide, setHide] = useState(false);

    const close = () => {
      setHide(true);
      markerRef.current?.hide();
      mapless?.setOpacity(1);
      onClose?.();
    };

    return (
      <MapboxMarker
        ref={markerRef}
        lngLat={position as LngLatLike}
        maplessRef={maplessRef}
        className={markerClassName}
        transparent
      >
        {destroyOnClose && hide
          ? undefined
          : contentProps && (
              <WrappedComponent
                {...(rest as P)}
                {...contentProps}
                onClose={close}
              />
            )}
      </MapboxMarker>
    );
  };

  Component.displayName = `withMapboxMarker(${WrappedComponent.displayName || WrappedComponent.name})`;
  return Component;
}

export default withMapboxMarker;
